#include "StdAfx.h"

PDFCreator::PDFCreator(HWND parent) :
  FilerFrogElement(parent)
{
	InitPDFCreator();
}

  PDFCreator::~PDFCreator()
{
	/* clean up */
	HPDF_Free(m_pdf);
}

bool PDFCreator::InitPDFCreator()
{
		m_pdf = HPDF_New(error_handler, NULL);

		if (!m_pdf)
		{
			printf("error: cannot create PdfDoc object\n");
			return false;
		}

		/* error-handler */
		if (setjmp(env))
		{
			HPDF_Free (m_pdf);
			return false;
		}

		HPDF_SetCompressionMode(m_pdf, HPDF_COMP_ALL);

		/* create default-font */
		m_font = HPDF_GetFont(m_pdf, "Helvetica", NULL);

		return true;
}

bool PDFCreator::CheckValidPDF(const wstring& fileName)
{
	const int PDF_VAR = 4;
	const int PDF_CONST = 2;

	if (!PathFileExists(wstring(fileName + FrogElementExt).c_str()))
	{
		return false;
	}

	SYSTEMTIME utilsobj = {0};
	UtilsObjCreate (&utilsobj);
	utilsobj.wHour = 0;
	utilsobj.wMilliseconds = 0;
	utilsobj.wMinute = 0;
	utilsobj.wSecond = 0;

	FileMachine read(NULL, L"c:\\lala.txt");
    ifstream in(wstring(fileName + FrogElementExt).c_str(), ios::binary);
	if (in.bad())
	{
		printf("BBABABAABABABBAABBABABABABABBABABABABABAB\n");
		return false;
	}
    //in.read((char*)&read, sizeof(read));
	in.seekg(sizeof(read));
	SYSTEMTIME utilsobj2 = {0};
	in.read((char*)&utilsobj2, sizeof(utilsobj2));
	utilsobj2.wHour = 0;
	utilsobj2.wMilliseconds = 0;
	utilsobj2.wMinute = 0;
	utilsobj2.wSecond = 0;

	in.close();

    double duplic1;
    double duplic2;

	CConvert::CConvertToDuplicator (&utilsobj, &duplic1);
	CConvert::CConvertToDuplicator (&utilsobj2, &duplic2);

	double dup = duplic1-duplic2;

    return (dup <= ((PDF_VAR*3) + PDF_CONST) && dup >= 0);
}

bool PDFCreator::DrawPage (const PDFPage& pagedefs)
{
	HPDF_Page page;
	HPDF_Destination dst;

	//if (pagedefs.ImageDefs.size() > 0)
	//{

	/* add a new page object and initialization */
	page = HPDF_AddPage (m_pdf);

	if (pagedefs.IsLandscape)
	{
		HPDF_Page_SetSize(page, (HPDF_PageSizes)pagedefs.Size, HPDF_PAGE_LANDSCAPE);
	}
	else
	{
		HPDF_Page_SetSize(page, (HPDF_PageSizes)pagedefs.Size, HPDF_PAGE_PORTRAIT);
	}

	HPDF_REAL pageWidth = HPDF_Page_GetWidth(page);
	HPDF_REAL pageHeight = HPDF_Page_GetHeight(page);
	
	HPDF_Page_SetRotate (page, pagedefs.Rotation);
	
	dst = HPDF_Page_CreateDestination (page);
	HPDF_Destination_SetXYZ (dst, 0, pageHeight, 1);
	HPDF_SetOpenAction(m_pdf, dst);
	/* finished page initialization */



	/* creating array of IMAGE_DEFINITIONS to access by index ad calulating stuff */
	IMAGE_DEFINITIONS* imgsdefs = new IMAGE_DEFINITIONS[pagedefs.ImageDefs.size()];
	HPDF_REAL totalWorH = 0;	// the total width or height according to IsLandscape
	HPDF_REAL maxWorH = 0;	// the max width or height according to IsLandscape
	int numImgs = 0;	// number of images in a row
	for(list<IMAGE_DEFINITIONS>::const_iterator iter=pagedefs.ImageDefs.begin(); iter!=pagedefs.ImageDefs.end(); iter++)
	{
		if (((*iter).ImageIdx<0) || ((*iter).ImageIdx>=(int)pagedefs.ImageDefs.size()))
		{
			wcout << L"wrong image index found" << endl;
			return false;
		}

		imgsdefs[(*iter).ImageIdx] = *iter;
		if ((imgsdefs[(*iter).ImageIdx].Width == -1) || (imgsdefs[(*iter).ImageIdx].Height == -1))
		{
			/* creating the image object */
			HPDF_Image image;
			image = HPDF_LoadJpegImageFromFileW (m_pdf, (*iter).FilePath.c_str());

			imgsdefs[(*iter).ImageIdx].Width = (HPDF_REAL)HPDF_Image_GetWidth (image);
			imgsdefs[(*iter).ImageIdx].Height = (HPDF_REAL)HPDF_Image_GetHeight (image);

			// adjust images' sizes if they go out of bounds
			if (pageWidth < imgsdefs[(*iter).ImageIdx].Width)
			{
				HPDF_REAL newimgw = pageWidth;
				HPDF_REAL z = imgsdefs[(*iter).ImageIdx].Width/newimgw;
				imgsdefs[(*iter).ImageIdx].Height /= z;
				imgsdefs[(*iter).ImageIdx].Width = newimgw;
			}
			if (pageHeight < imgsdefs[(*iter).ImageIdx].Height)
			{
				HPDF_REAL newimgh = pageHeight;
				HPDF_REAL z = imgsdefs[(*iter).ImageIdx].Height/newimgh;
				imgsdefs[(*iter).ImageIdx].Width /= z;
				imgsdefs[(*iter).ImageIdx].Height = newimgh;
			}
		}
		
		if ((imgsdefs[(*iter).ImageIdx].LocX == -1) || (imgsdefs[(*iter).ImageIdx].LocY == -1))
		{
			HPDF_REAL forT = (pagedefs.ImgsLeftToRight? imgsdefs[(*iter).ImageIdx].Width : imgsdefs[(*iter).ImageIdx].Height);
			HPDF_REAL forM = (pagedefs.ImgsLeftToRight? imgsdefs[(*iter).ImageIdx].Height : imgsdefs[(*iter).ImageIdx].Width);
			totalWorH += forT;
			maxWorH = max(maxWorH, forM);
			numImgs++;
		}
	}

	HPDF_REAL* rowimgsWorH = new HPDF_REAL[numImgs];
	HPDF_REAL netoPW = pageWidth - (pagedefs.Margin*(numImgs+1));	// neto page width. 
														//without margines and space between images which is now set to 28 HPDF_REAL (about 1cm).
	HPDF_REAL netoPH = pageHeight - (pagedefs.Margin*(numImgs+1));	// neto page height. the same as for width.
	HPDF_REAL netoWorHpage = (pagedefs.ImgsLeftToRight? netoPW : netoPH);
	HPDF_REAL rel = 1;
	if (totalWorH > netoWorHpage)
		rel = netoWorHpage / totalWorH;

	// updating sizes and totalWorH
	totalWorH = 0;
	maxWorH = 0;
	for(int i=0; i<numImgs; i++)
	{
		imgsdefs[i].Width *= rel;
		imgsdefs[i].Height *= rel;

		rowimgsWorH[imgsdefs[i].ImageIdx] = (pagedefs.ImgsLeftToRight? imgsdefs[i].Width : imgsdefs[i].Height);
		HPDF_REAL forT = (pagedefs.ImgsLeftToRight? imgsdefs[i].Width : imgsdefs[i].Height);
		HPDF_REAL forM = (pagedefs.ImgsLeftToRight? imgsdefs[i].Height : imgsdefs[i].Width);
		totalWorH += forT;
		maxWorH = max(maxWorH, forM);
	}

	// updating locations
	HPDF_REAL otherWorHpage = (pagedefs.ImgsLeftToRight? pageHeight : pageWidth);
	HPDF_REAL margin = (otherWorHpage-maxWorH) / 2;
	while (margin<pagedefs.Margin)
	{
		HPDF_REAL newMax = 0;
		for(int i=0; i<numImgs; i++)
		{
			HPDF_REAL imgWorH = pagedefs.ImgsLeftToRight? imgsdefs[i].Height : imgsdefs[i].Width;
			if (imgWorH == maxWorH)
			{
				HPDF_REAL newimgwh =  (pagedefs.ImgsLeftToRight? pageHeight : pageWidth);
				newimgwh-=(pagedefs.Margin*2);
				totalWorH -= (imgWorH-newimgwh);
				HPDF_REAL z = imgWorH/newimgwh;
				imgsdefs[i].Height /= z;
				imgsdefs[i].Width /= z;
				rowimgsWorH[i] = (pagedefs.ImgsLeftToRight? imgsdefs[i].Width : imgsdefs[i].Height);

				imgWorH = pagedefs.ImgsLeftToRight? imgsdefs[i].Height : imgsdefs[i].Width;
			}
			
			if (imgWorH > newMax)
			{
				newMax = imgWorH;
			}
		}
		maxWorH = newMax;

		margin = (otherWorHpage-maxWorH) / 2;
	}
	HPDF_REAL brutoWorHpage = (pagedefs.ImgsLeftToRight? pageWidth : pageHeight);
	HPDF_REAL gap = (brutoWorHpage-totalWorH) / (numImgs+1);
	HPDF_REAL x = (pagedefs.ImgsLeftToRight? gap : margin);
	HPDF_REAL y = (pagedefs.ImgsLeftToRight? margin : gap);
	for(int i=0; i<numImgs; i++)
	{
		imgsdefs[i].LocX = (pagedefs.ImgsLeftToRight? x : max(margin, ((pageWidth-imgsdefs[i].Width) / 2)));
		imgsdefs[i].LocY = (pagedefs.ImgsLeftToRight? max(margin, ((pageHeight-imgsdefs[i].Height) / 2)) : y);
		
		HPDF_REAL offset = gap + rowimgsWorH[i];
		if (pagedefs.ImgsLeftToRight)
			x += offset;
		else
			y += offset;
	}

	/* drawing images in page */
	for(int i=0; i<(int)pagedefs.ImageDefs.size(); i++)
	{
		/* creating the image object */
		HPDF_Image image;
		image = HPDF_LoadJpegImageFromFileW (m_pdf, imgsdefs[i].FilePath.c_str());
		
		HPDF_Page_DrawImage (page, image, imgsdefs[i].LocX, imgsdefs[i].LocY, imgsdefs[i].Width, imgsdefs[i].Height);

		if (imgsdefs[i].DrawBorders)
		{
			HPDF_Page_Rectangle  (page,
									  imgsdefs[i].LocX -5,
									  imgsdefs[i].LocY -5,
									  imgsdefs[i].Width + 10,
									  imgsdefs[i].Height + 10);
			HPDF_Page_Stroke (page);
		}

	}

	delete[] rowimgsWorH;
	delete[] imgsdefs;

	return true;
}


bool PDFCreator::Go(PDFFile& pdfFile)
{
	/* check if dest path exists and delete it */
	if (PathFileExists(pdfFile.FilePath.c_str()))
	{
		wstring msg(L"The file: " + wstring(pdfFile.FilePath) + L" already exists.\nTrying to send it to the recycle bin.");
		FilesRefactorUtils::FrogMessageBox(m_parent, msg.c_str(), L"File Already Exists", MB_OK|MB_ICONSTOP);
		DeleteFileOperation dfo(m_parent, pdfFile.FilePath.c_str(), false, true, true);
		if (!dfo.Execute())
		{
			wstring msg(L"The file: " + wstring(pdfFile.FilePath) + L" might be in use.\nCan't complete operation!");
			FilesRefactorUtils::FrogMessageBox(m_parent, msg.c_str(), L"File In Use", MB_OK|MB_ICONSTOP);
			return false;
		}
	}

	for(list<PDFPage>::iterator iter = pdfFile.Pages.begin(); iter!=pdfFile.Pages.end(); iter++)
	{
		if ((*iter).ImageDefs.size() == 0)
		{
			wcout << L"No images for page while validating JPG" << endl;
			continue;
		}

		for(list<IMAGE_DEFINITIONS>::iterator iter1 = (*iter).ImageDefs.begin(); iter1!=(*iter).ImageDefs.end(); iter1++)
		{
			if (!PathFileExists((*iter1).FilePath.c_str()))
			{
				wcout << L"Some image files doesn't exist" << endl;
				return false;				
			}

			FileMachine fm(m_parent, (*iter1).FilePath);
			
			wstring ext;
			fm.Extension(ext);

			for(wstring::iterator i = ext.begin(); i != ext.end(); ++i)
			{
				*i = (wchar_t)tolower(*i);
			}

			if (ext != L"jpg")
			{
				wcout << L"Some files are not JPG" << endl;
				return false;
			}

			if ((*iter).OptimizeImages)
			{
				FileMachine fm(m_parent, iter1->FilePath);

				wchar_t tmpPath[MAX_PATH];
				GetTempPath(MAX_PATH, tmpPath);
				
				wstring namepext;
				fm.NamePlusExt(namepext);
				wstring destFile(wstring(tmpPath) + L"\\" + namepext);
				
				CopyFileOperation cfo(m_parent, iter1->FilePath.c_str(), destFile.c_str(), false, true);
				cfo.Execute();
				
				HPDF_REAL width;
				HPDF_REAL height;
				FilesRefactorUtils::GetImageSize(&width, &height, iter1->FilePath.c_str());

				FileResizer fr(m_parent, (int)iter1->Width, (int)iter1->Height);
				list<wstring> tmp;
				fr.Resize(destFile.c_str(), 100, L"", false, tmp, L"");

				iter1->FilePath = destFile;
			}
		}
	}

	for(list<PDFPage>::iterator iter = pdfFile.Pages.begin(); iter!=pdfFile.Pages.end(); iter++)
	{
		if ((*iter).ImageDefs.size() == 0)
		{
			wcout << L"No images for page" << endl;
			continue;
		}
		DrawPage(*iter);

		if (iter->OptimizeImages)
		{
			for(list<IMAGE_DEFINITIONS>::iterator iter1 = iter->ImageDefs.begin(); iter1!=iter->ImageDefs.end(); iter1++)
			{
				DeleteFileOperation dfo(m_parent, iter1->FilePath.c_str(), false, true, false);
				dfo.Execute();
			}
		}
	}

	char tmpPath[512];
	GetTempPathA(512, tmpPath);
	char cPath[MAX_PATH];
	GetTempFileNameA(tmpPath, "obg", 0, cPath);
	
	/* convert char* path to wchar_t* path */
	wchar_t wcsPath[MAX_PATH];
	FilesRefactorUtils::Char2Wchar(wcsPath, cPath);

	DeleteFileOperation dfo(m_parent, wcsPath, false, true, false);
	dfo.Execute();

	/* save the document to a file */
	HPDF_SaveToFile(m_pdf, cPath);

	/* move to destination */
	MoveFileOperation mfo(m_parent, wcsPath, pdfFile.FilePath.c_str(), false, false);
	mfo.Execute();
	
	return true;
}

